package com.simen.album;

import android.animation.Animator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ViewGroup;
import android.view.WindowManager;

import java.io.File;

/**
 * Created by zhangming on 16/6/29.
 */
public class AlbumView extends GestureView {
    public final static String TAG = AlbumView.class.getCanonicalName();
    private final int ScreenWidth, ScreenHeight;
    public final static int DURATION = 300;
    private String path;
    private Drawable drawable;
    private RectF bounds = new RectF();//目标区域
    private RectF cropRect = null; //绘制区域
    private boolean press = false;//判断当前图片是否被触摸
    private boolean scale = false;//判断是否处在缩放模式
    private float mScaleValue = 1f;//缩放模式下的缩放值
    private Rect startloc;
    ValueAnimator animator = new ValueAnimator();//加载时的渐进动画计算
    private OnClickListener onClickListener;
    private OnAnimatorEndListener onAnimatorEndListener;
    private boolean isScaling = false;

    public interface OnAnimatorEndListener {//取消动画回调接口

        /**
         * 取消动画回调
         * @param albumView
         */
        void scaleAnimationEnd(AlbumView albumView);
    }

    /**
     * 实例化Album并附着在rootView上
     *
     * @param activity 要附着的window
     * @param color    设置背景色
     * @return Album实例
     */
    public static AlbumView attachWindow(Activity activity, int color) {
        AlbumView album = new AlbumView(activity);
        album.setBackgroundColor(color);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        ((ViewGroup) activity.getWindow().getDecorView()).addView(album, layoutParams);
        return album;
    }

    public AlbumView(Context context) {
        this(context, null);
    }

    public AlbumView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AlbumView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //获取屏幕数据
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Point point = new Point();
        windowManager.getDefaultDisplay().getSize(point);
        ScreenWidth = point.x;
        ScreenHeight = point.y;
    }

    /**
     * @param localpath 图片路径
     * @param startloc  起始区域
     */
    public void setImage(String localpath, Rect startloc) {
        File imgFile = new File(localpath);
        if (!imgFile.exists()) {
            return;
        }

        if (!imgFile.isFile()) {
            return;
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(localpath, options);

        if (this.isScaling) {
            Log.i(TAG, "setImage: current view is scaling,fail to set new image");
            return;
        }

        //对比图片和屏幕宽高比,选择合适的目标尺寸
        double widthScale = ScreenWidth * 1.0 / options.outWidth;
        double heightScale = ScreenHeight * 1.0 / options.outHeight;
        double height = options.outHeight * widthScale;
        double width = options.outWidth * heightScale;

        if (options.outWidth > ScreenWidth || options.outHeight > ScreenHeight) {
            Log.i(TAG, "setImage: imagesize is too large," + options.outWidth + "x" + options.outHeight);
            double rateScreen = ScreenHeight * 1.0 / ScreenWidth;
            double rateImg = options.outHeight * 1.0 / options.outWidth;
            if (rateScreen > rateImg) {//以屏幕宽度为准
                this.bounds.set(0, (float) ((ScreenHeight - height) / 2), ScreenWidth, (float) ((ScreenHeight - height) / 2 + height));
            } else {//以屏幕高度为准
                this.bounds.set((float) ((ScreenWidth - width) / 2), 0, (float) ((ScreenWidth - width) / 2 + width), ScreenHeight);
            }
        } else {
            this.bounds.set(0, (float) ((ScreenHeight - height) / 2), ScreenWidth, (float) ((ScreenHeight - height) / 2 + height));
        }

        this.path = localpath;
        this.startloc = startloc;
        this.drawable = Drawable.createFromPath(localpath);

        this.cropRect = null;
        if (animator.isRunning()) {
            animator.cancel();
        }
        animator.removeAllUpdateListeners();
        animator.removeAllListeners();
        if (startloc != null) {//开始动画
            animator.setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("left", startloc.left, (int) bounds.left),
                    PropertyValuesHolder.ofInt("top", startloc.top, (int) bounds.top),
                    PropertyValuesHolder.ofInt("right", startloc.right, (int) bounds.right),
                    PropertyValuesHolder.ofInt("bottom", startloc.bottom, (int) bounds.bottom)});
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    bounds.set((int) animation.getAnimatedValue("left"), (int) animation.getAnimatedValue("top"),
                            (int) animation.getAnimatedValue("right"), (int) animation.getAnimatedValue("bottom"));
                    invalidate();
                }
            });
            animator.setDuration(DURATION);
            animator.start();
        } else {
            invalidate();
        }
    }

    /**
     * 用于取消图片展示,开始缩放动画
     *
     * @param onAnimatorEndListener 缩放结束回调
     */
    public void cancelView(OnAnimatorEndListener onAnimatorEndListener) {
        if (startloc == null || animator.isRunning() || this.isScaling) {
            return;
        }
        this.isScaling = true;
        this.onAnimatorEndListener = onAnimatorEndListener;

        animator.setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("left", (int) bounds.left, startloc.left),
                PropertyValuesHolder.ofInt("top", (int) bounds.top, startloc.top),
                PropertyValuesHolder.ofInt("right", (int) bounds.right, startloc.right),
                PropertyValuesHolder.ofInt("bottom", (int) bounds.bottom, startloc.bottom)});
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                bounds.set((int) animation.getAnimatedValue("left"), (int) animation.getAnimatedValue("top"),
                        (int) animation.getAnimatedValue("right"), (int) animation.getAnimatedValue("bottom"));
                invalidate();
            }
        });
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                isScaling = false;
                if (AlbumView.this.onAnimatorEndListener != null) {
                    AlbumView.this.onAnimatorEndListener.scaleAnimationEnd(AlbumView.this);
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                isScaling = false;
                if (AlbumView.this.onAnimatorEndListener != null) {
                    AlbumView.this.onAnimatorEndListener.scaleAnimationEnd(AlbumView.this);
                }
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animator.setDuration(DURATION);
        animator.start();
    }

    @Override
    public void setOnClickListener(OnClickListener l) {
        this.onClickListener = l;
    }

    @Override
    protected boolean onSingleTapConfirmed(MotionEvent e) {
        if (onClickListener != null) {
            onClickListener.onClick(this);
        }
        return super.onSingleTapConfirmed(e);
    }

    @Override
    protected boolean onDown(MotionEvent e) {
        if (cropRect != null && !animator.isRunning()) {
            press = cropRect.contains(e.getX(), e.getY());
        }
        return super.onDown(e);
    }

    @Override
    protected boolean onUp(MotionEvent e) {
        press = false;
        return super.onUp(e);
    }

    @Override
    protected boolean onDoubleTap(MotionEvent e) {
        if (!animator.isRunning()) {
            cropRect = new RectF(bounds);
            invalidate();
        }
        return true;
    }

    @Override
    protected boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        if (press && !animator.isRunning()) {//用户移动图片
            cropRect.offset(-(int) distanceX, -(int) distanceY);
            invalidate();
        }
        return super.onScroll(e1, e2, distanceX, distanceY);
    }

    @Override
    protected boolean onScaleBegin(ScaleGestureDetector detector) {
        scale = true;
        return super.onScaleBegin(detector);
    }

    @Override
    protected boolean onScale(ScaleGestureDetector detector) {
        float scalefactor = detector.getScaleFactor();
        if (scalefactor != 1f && !animator.isRunning()) {
            this.mScaleValue = scalefactor;
            invalidate();
            return true;
        }
        return super.onScale(detector);
    }

    @Override
    protected void onScaleEnd(ScaleGestureDetector detector) {
        scale = false;
        super.onScaleEnd(detector);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (drawable != null) {
            if (!animator.isRunning()) {//动画已结束,开启手动模式
                drawable.setBounds(scale ? getScaleRect() : getCropRect());
            } else {
                Rect rect = new Rect();
                bounds.round(rect);
                drawable.setBounds(rect);
            }
            drawable.draw(canvas);
        }
    }

    /**
     * 刷新新的绘制区域
     *
     * @return
     */
    public Rect getCropRect() {
        if (cropRect == null) {
            cropRect = new RectF(bounds);
        }
        Rect rect = new Rect();
        cropRect.round(rect);
        return rect;
    }

    /**
     * 刷新缩放模式下的缩放数据
     *
     * @return
     */
    private Rect getScaleRect() {
        Matrix scaleMatrix = new Matrix();
        scaleMatrix.postTranslate(-cropRect.centerX(), -cropRect.centerY());
        scaleMatrix.postScale(mScaleValue, mScaleValue);
        scaleMatrix.postTranslate(cropRect.centerX(), cropRect.centerY());
        RectF rectF = new RectF(cropRect);
        scaleMatrix.mapRect(rectF);
        float rate = rectF.width() / bounds.width();
        if (rate >= 0.5 && rate <= 1.5) {//最小只能缩小到目标尺寸的0.5倍,最大只能缩小到目标尺寸的1.5倍
            cropRect.set(rectF);
        }
        Rect rect = new Rect();
        cropRect.round(rect);
        return rect;
    }
}
